<template>
  <div class="comp-h-form">
    <a-form-model
      ref="form"
      :label-col="{ span: labelCol }"
      :wrapper-col="{ span: wrapperCol }"
      :model="formData"
    >
      <template v-for="(item, i) in items">
        <div
          v-if="item.type === 'label' && item.labelbutton !== true"
          :key="i"
          class="form-label-item label"
          :class="item.isUp ? 'close' : 'open'"
          @click="toggleGroup(item, i)"
        >
          {{ item.label }}
          <a-icon class="up-down" :type="item.isUp ? 'down' : 'up'" />
        </div>
        <div
          v-else-if="item.type === 'label' && !item.isHide"
          :key="i"
          class="form-label-item label close"
        >
          {{ item.label }}
          <a-switch
            :key="`form-item-${i}`"
            v-model="formData[item.props[0].name]"
            class="label-switch"
            :label="item.props[0].label"
            v-bind="item.props[0].bind || {}"
            :form-data="formData"
            :name="item.props[0].name"
            :props="item.props[0].props"
            :size="item.props[0].size ? item.props[0].size : 'small'"
            :disabled="
              item.isDisableSub ||
              (item.props &&
                item.props[0] &&
                item.props[0].props &&
                item.props[0].props.disabled)
            "
            @change="
              (val) => {
                formItemChange(val, item.props[0].name, item.props[0])
              }
            "
            @update-form-data="updateFormData"
          />
        </div>
        <a-form-model-item
          v-else-if="item.type === 'inputNumber'"
          v-show="!item.isHide"
          :key="`form-item-${i}`"
          :class="{
            'multiple-select': item.type === 'multipleSelect',
            switch: item.type == 'switch',
          }"
          :label="item.label"
        >
          <a-input-number
            :key="i"
            v-model="formData[item.name]"
            class="h-input-number"
            v-bind="item.bind"
            :form-data="formData"
            :name="item.name"
            :label="item.label"
            :props="item.props"
            :size="item.size ? item.size : 'small'"
            :disabled="item.props && item.props.disabled"
            @pressEnter="
              (val) => {
                formItemPressEnter(val, item.name, item)
              }
            "
            @blur="
              (val) => {
                formItemChange(val, item.name, item)
              }
            "
            @update-form-data="updateFormData"
          ></a-input-number>
        </a-form-model-item>
        <!-- <a-form-model-item v-else-if="item.type === 'themeRadio'"  v-show="!item.isHide"  :key="`form-item-${i}`" class="icon-radio" :label="item.label" > -->
        <div
          v-else-if="item.type === 'iconRadio'"
          v-show="!item.isHide"
          :key="`form-item-${i}`"
          class="icon-radio"
        >
          <div class="form-item-title">{{ item.label }}</div>
          <component
            :is="getCompType(item)"
            v-model="formData[item.name]"
            v-bind="
              item.bind || {
                ...item.bind,
                ...(['multipleSelect', 'checkboxGroup'].includes(item.type)
                  ? item.props
                  : {}),
              }
            "
            :form-data="formData"
            :config-type="configType"
            :name="item.name"
            :label="item.label"
            :props="getRadioProps(item)"
            :size="item.size ? item.size : 'small'"
            :disabled="
              ['checkboxGroup'].includes(item.type)
                ? item.bind && item.bind.disabled
                : item.props && item.props.disabled
            "
            @change="
              (val) => {
                formItemChange(val, item.name, item)
              }
            "
            @update-form-data="updateFormData"
          ></component>
        </div>
        <!-- </a-form-model-item> -->
        <br v-else-if="item.type === 'br'" :key="i" />
        <a-form-model-item
          v-show="!item.isHide"
          v-else
          :key="`form-item-${i}`"
          :class="getItemClass(item, i)"
          :label="item.label"
        >
          <component
            :is="getCompType(item)"
            v-model="formData[item.name]"
            v-bind="
              item.bind || {
                ...item.bind,
                ...(['multipleSelect', 'checkboxGroup'].includes(item.type)
                  ? item.props
                  : {}),
              }
            "
            :form-data="formData"
            :name="item.name"
            :label="item.label"
            :props="item.props"
            :size="item.size ? item.size : 'small'"
            :disabled="
              ['checkboxGroup'].includes(item.type)
                ? item.bind && item.bind.disabled
                : item.props && item.props.disabled
            "
            @change="
              (val) => {
                formItemChange(val, item.name, item)
              }
            "
            @blur="
              () => {
                formItemBlur(item.name, item)
              }
            "
            @update-form-data="updateFormData"
          >
            <template v-if="['select', 'a-select'].includes(item.type)">
              <a-select-option
                v-for="(option, index) in item.props.options"
                :key="index"
                :disabled="option.disabled"
                :value="option.value"
              >
                {{ option.text }}
              </a-select-option>
            </template>
          </component>
          <!-- 附属组件 -->
          <div
            v-if="item.subItems && item.subItems.length > 0"
            class="sub-box"
            :style="item.subStyle ? item.subStyle : {}"
          >
            <template v-for="(itemSub, k) in item.subItems">
              <span
                v-if="itemSub.type === 'sort'"
                v-bind="itemSub.bind"
                :key="k"
                class="btn sort-box"
              >
                <a-icon
                  class="sort-item"
                  :class="{
                    active:
                      formData[itemSub.name] &&
                      formData[itemSub.name] === 'asc',
                    disabled: itemSub.disabled || !formData[item.name],
                  }"
                  type="caret-up"
                  title="升序"
                  @click="
                    subItemChange(
                      itemSub,
                      'asc',
                      itemSub.disabled || !formData[item.name]
                    )
                  "
                />
                <a-icon
                  class="sort-item"
                  :class="{
                    active:
                      formData[itemSub.name] &&
                      formData[itemSub.name] === 'desc',
                    disabled: itemSub.disabled || !formData[item.name],
                  }"
                  type="caret-down"
                  title="降序"
                  @click="
                    subItemChange(
                      itemSub,
                      'desc',
                      itemSub.disabled || !formData[item.name]
                    )
                  "
                />
              </span>
            </template>
          </div>
        </a-form-model-item>
      </template>
    </a-form-model>
  </div>
</template>
<script lang="ts" type="text/tsx">
import { isArray, isString, isUndefined } from 'lodash'
import { Component, Prop, Vue, Watch } from 'vue-property-decorator'
import ThemeColorRadio from '@/components/controlSetter/material/ThemeColorRadio.vue'
import IconRadio from '@/components/form/IconRadio.vue'
import MultipleSelect from '@/components/form/multiple-select.vue'
import ColorPicker from '@/components/form/color-picker.vue'
import paddingSetter from '@/components/form/padding.vue'
import visualizationStore from '@/store/modules/visualization'
import rangeMonth from '@/components/form/rangeMonth.vue'
import rangeYear from '@/components/form/rangeYear.vue'
import rangeDay from '@/components/form/rangeDay.vue'
import columnSelector from './column-selector.vue'
import KV from './kv'

@Component({
  components: {
    ThemeColorRadio,
    MultipleSelect,
    ColorPicker,
    paddingSetter,
    rangeMonth,
    rangeYear,
    rangeDay,
    columnSelector,
    IconRadio,
  },
})
export default class Hform extends Vue {
  private compMaps: KV = {
    colorPicker: {
      component: 'color-picker',
      props: {},
    },
    multipleSelect: {
      component: 'multiple-select',
      props: {},
    },
    inputNumber: {
      component: 'a-input-number',
      props: {},
    },
    text: {
      component: 'a-input',
      props: {},
    },
    radioGroup: {
      component: 'a-radio-group',
      props: {},
    },
    checkboxGroup: {
      component: 'a-checkbox-group',
      props: {},
    },
    select: {
      component: 'a-select',
      props: {
        defaultChecked: false,
        disabled: false,
      },
    },
    switch: {
      component: 'a-switch',
      props: {
        checked: false,
      },
    },
    themeColorRadio: {
      component: 'theme-color-radio',
      props: {},
    },
    paddingSetter: {
      component: 'padding-setter',
      props: {},
    },
    rangePicker: {
      component: 'a-range-picker',
      props: {},
    },
    rangeYear: {
      component: 'rangeYear',
      props: {},
    },
    rangeMonth: {
      component: 'rangeMonth',
      props: {},
    },
    rangeDay: {
      component: 'rangeDay',
      props: {},
    },
    columnSelector: {
      component: 'columnSelector',
      props: {},
    },
    iconRadio: {
      component: 'icon-radio',
      props: {},
    },
  }
  @Prop({
    type: Array,
    required: true,
    default(): Array<KV> {
      return []
    },
  })
  items!: Array<KV>

  @Prop({
    type: Object,
    required: true,
    default(): object {
      return {}
    },
  })
  formData!: object

  @Prop({
    type: Object,
    required: false,
    default(): object {
      return {
        layout: 'horizontal',
      }
    },
  })
  form!: object

  @Prop({
    type: Number,
    required: false,
    default() {
      return 8
    },
  })
  labelCol!: number

  @Prop({
    type: Number,
    required: false,
    default() {
      return 16
    },
  })
  wrapperCol!: number

  @Prop({
    type: String,
    required: false,
    default() {
      return ''
    },
  })
  chartType!: string

  @Prop({
    type: String,
    required: false,
    default() {
      return ''
    },
  })
  configType!: string

  @Watch('items', { deep: true })
  setFormItems() {
    setTimeout(() => {
      this.initFormData()
    }, 10)
  }

  mounted() {
    this.initFormData()
  }

  toggleGroup(item: any, i: number) {
    this.items[i].isUp = !this.items[i].isUp
    /* eslint-disable */
    for (let j = i + 1; j < this.items.length; j++) {
      if (this.items[j].type === 'label') {
        break
      }
      this.$set(this.items[j], 'isHide', this.items[i].isUp)
    }
    this.$emit('toggleGroup', {
      item,
      isUp: this.items[i].isUp,
    })
  }

  getItemClass(item: KV, i: number) {
    let result = ''
    switch (item.type) {
      case 'paddingSetter':
        result += ' padding-setter'
        break
      case 'multipleSelect':
        result += ' multiple-select'
        break
      case 'switch':
        result += ' switch'
        break

      default:
        break
    }
    if (i > 0 && this.items[i - 1].type === 'switch') {
      result += ' switch-fix'
    }

    if (isString(item.class)) {
      result += ` ${item.class}`
    }

    if (item.bind && isString(item.bind.class)) {
      result += ` ${item.bind.class}`
    }
    return result
  }

  initFormData() {
    this.items.forEach((item: KV) => {
      if ((this.formData as KV)[item.name] === undefined) {
        this.$set(
          this.formData,
          item.name,
          isUndefined(item.value) ? '' : item.value
        )
        if (
          item.subItems &&
          isArray(item.subItems) &&
          item.subItems.length > 0
        ) {
          item.subItems.forEach((subItem) => {
            this.$set(
              this.formData,
              subItem.name,
              isUndefined(subItem.value) ? '' : subItem.value
            )
          })
        }
      }
    })
  }

  getCompType(item: KV): string {
    const result = 'a-input'
    if (this.compMaps[item.type]) {
      return this.compMaps[item.type].component
    }
    return result
  }

  // 需要根据类型分类讨论
  formItemChange(value: any, key: string, item: KV) {
    let chartOptions: any =
      this.configType === 'dataView'
        ? this.formData
        : visualizationStore.currentGridItem?.chartOptions
    if (chartOptions) {
      if (key === 'axisLayout') {
        // xattribute
        // yattribute
        // axisCategoricalDataSelection
        if (value != chartOptions.axisLayout) {
          let xAttribute = chartOptions.yAxisAttribute
          let yAttribute = chartOptions.xAxisAttribute
          let chartType =
            this.configType === 'dataView'
              ? this.chartType
              : visualizationStore.currentGridItem?.chartType[1]
          if (
            chartType !== undefined &&
            ['groupBarChart', 'stackBarChart'].includes(chartType)
          ) {
            if (typeof xAttribute === 'string') {
              xAttribute = [xAttribute]
            }
            if (typeof yAttribute === 'string') {
              yAttribute = [yAttribute]
            }
          }
          const type = chartOptions.axisCategoricalDataSelection
          this.$emit('change', xAttribute, 'xAxisAttribute', item)
          this.$emit('change', yAttribute, 'yAxisAttribute', item)
          this.$emit(
            'change',
            value === 'vertical' ? 'yAxis' : 'xAxis',
            'axisCategoricalDataSelection',
            item
          )
          this.$emit(
            'change',
            value === 'vertical' ? 'top' : 'bottom',
            'xAxisPosition',
            item
          )
        }
      } else if (key === 'axisGridIsShow') {
        this.$emit('change', value, 'xAxisGridIsShow', item)
        this.$emit('change', value, 'yAxisGridIsShow', item)
      }
      this.$emit('change', value, key, item)
    }
  }

  formItemBlur(key: string, item: KV) {
    this.$emit('blur', key, item)
  }

  formItemPressEnter(event: any, key: string, item: KV) {
    const value = event.target.value
    this.$emit('change', value, key, item)
  }

  // 更新自定义组件绑定的formData中的值
  updateFormData(value: any, key: string) {
    let chartOptions: any =
      this.configType === 'dataView'
        ? this.formData
        : visualizationStore.currentGridItem?.chartOptions
    if (chartOptions) {
      if (key === 'axisLayout') {
        if (value != chartOptions.axisLayout) {
          let xAttribute = chartOptions.yAxisAttribute
          let yAttribute = chartOptions.xAxisAttribute
          let chartType = this.chartType
          if (['groupBarChart', 'stackBarChart'].includes(chartType)) {
            if (typeof xAttribute === 'string') {
              xAttribute = [xAttribute]
            }
            if (typeof yAttribute === 'string') {
              yAttribute = [yAttribute]
            }
          }
          const type = chartOptions.axisCategoricalDataSelection
          this.$set(this.formData, 'xAxisAttribute', xAttribute)
          this.$set(this.formData, 'yAxisAttribute', yAttribute)
          this.$set(
            this.formData,
            'axisCategoricalDataSelection',
            value === 'vertical' ? 'yAxis' : 'xAxis'
          )
          this.$set(
            this.formData,
            'xAxisPosition',
            value === 'vertical' ? 'top' : 'bottom'
          )
        }
      } else if (key === 'axisGridIsShow') {
        // 判断离散类型
        const type = chartOptions.axisCategoricalDataSelection
        if (['xAxis', 'yAxis'].includes(type)) {
          this.$set(
            this.formData,
            `${type === 'xAxis' ? 'yAxis' : 'xAxis'}GridIsShow`,
            value
          )
        } else if (type === 'all') {
          this.$set(this.formData, 'xAxisGridIsShow', value)
          this.$set(this.formData, 'yAxisGridIsShow', value)
        }
      }

      this.$set(this.formData, key, value)
    }
  }
  subItemChange(item: KV, mod: string, disabled: boolean) {
    if (disabled) {
      return
    }
    this.$set(this.formData, item.name as string, mod)
    this.$emit('change', mod, item.name as string, item)
  }

  public getRadioProps(item: any) {
    item.props.configType = this.configType
    if (this.configType === 'dataView') {
      item.props.target = (this.formData as any)[item.props.name]
    } else if (visualizationStore.currentGridItem) {
      item.props.target =
        visualizationStore.currentGridItem.chartOptions[item.props.name]
    }
    return item.props
  }
}
</script>
<style lang="less" scoped>
/deep/ .ant-form-item {
  margin-bottom: 0;
}

/deep/ .comp-range-day {
  min-width: 400px;
  padding-top: 8px;

  .spliter {
    height: 24px;
  }
}

.form-label-item {
  background: #f9f9fc;
  border-top: 1px solid #e9e9e9;
  color: #5d637e;
  font-size: 14px;
  font-weight: bold;
  height: 36px;
  letter-spacing: 1px;
  line-height: 36px;
  margin-top: 8px;
  padding-left: 20px;
  transition: all ease-in 0.1s;

  &.label {
    background: #f9f9fc;
  }

  &.close {
    margin-bottom: -8px;
  }

  .up-down {
    color: rgba(93, 99, 126, 1);
    float: right;
    font-size: 14px;
    line-height: 36px;
    margin-right: 10px;
  }

  .label-switch {
    float: right;
    margin-right: 10px;
    margin-top: 10px;
  }

  &:first-child {
    border-top: 1px solid transparent;
    margin-top: 0;
  }
}

.form-label-item + .ant-form-item {
  margin-top: 8px;
}

/deep/ .ant-form-item label {
  color: #222432;
  font-size: 14px;
  font-weight: 400;
  letter-spacing: 1px;
  line-height: 17px;
  // opacity: 0.6;
}

/deep/ .ant-form-item-label > label::after {
  display: none;
}

/deep/ .ant-form-item-label {
  padding-left: 10px;
  text-align: left;
}

/deep/ .ant-row.ant-form-item {
  padding: 0 10px 0 8px !important;

  &.switch {
    width: 50%;

    .ant-col-8,
    .ant-col-16 {
      box-sizing: border-box;
      margin: 0;
    }

    .ant-col-8 {
      padding-left: 10px;
      width: 60%;
    }

    .ant-col-16 {
      padding-left: 20px;
      width: 40%;
    }

    // &.switch-fix {
    //   clear: both;
    //   float: right;
    //   margin-top: -39px;
    // }
  }

  &.switch + .switch {
    float: right;
    margin-top: -39px;
  }
  // &.switch:nth-child(2n) {
  //   float: right;
  //   margin-top: -39px;
  // }

  &.multiple-select {
    .ant-form-item-control {
      height: auto;
    }
  }

  .ant-form-item-control {
    height: 30px;
  }

  .h-input-number {
    width: 170px;
  }
}

.btn {
  border: 1px solid #eaeaea;
  color: #555;
  cursor: pointer;
  font-size: 13px;
  height: 24px;
  line-height: 24px;
  margin-left: 2px;
  padding: 0 2px;

  &:hover {
    border-color: #5760e6;
    color: #5760e6;
  }

  &.disabled {
    border-color: #eaeaea;
    color: #888;
    cursor: not-allowed;

    &:hover {
      border-color: #eaeaea;
      color: #888;
    }
  }

  &.sort-box {
    border-color: transparent;
    display: block;
    height: 32px;
    padding: 0;
    width: 16px;

    &:hover {
      border-color: transparent;
      color: #888;
    }

    .sort-item {
      border: 1px solid #eaeaea;
      color: #888;
      display: inline-block;
      float: left;
      font-size: 10px;
      height: 10px;
      line-height: 10px;
      width: 16px;
      width: 100%;

      &.active {
        color: #333;
      }

      &:hover {
        border-color: #5760e6;
        color: #5760e6;
      }

      &.disabled {
        cursor: not-allowed !important;

        &.active {
          color: #888;
        }

        &:hover {
          border: 1px solid #eaeaea;
          color: #888;
        }
      }

      &:first-child {
        margin-bottom: 2px;
      }
    }
  }
}

.icon-radio {
  padding-left: 8px;
  padding-right: 10px;
}

/deep/ .form-item-title {
  color: #222432;
  font-size: 14px;
  font-weight: 600;
  height: 39px;
  letter-spacing: 1px;
  line-height: 39px;
  opacity: 0.6;
  padding-left: 10px;
}
</style>
